package org.ihelpuoo.parser.segment;

import org.apache.commons.collections.ArrayStack;

public final class MarkStack
{

	private ArrayStack	ms	= new ArrayStack();

	private Marks		marks;

	public MarkStack()
	{
		this.marks = Marks.instance();
	}

	/**
	 * Test current char can be appended to buffer or not. It depends one its private
	 * stack. The cases are listed below:
	 * <p>
	 * <table border="0" cellspacing="1" cellpadding="2">
	 * <tr bgcolor="#f0f0f0" style="font-weight:bold;" align="center">
	 * 		<td>Stack.peek()</td>
	 * 		<td>Comment</td>
	 * </tr>
	 * <tr>
	 * 		<td><i>EMPTY</i></td>
	 * 		<td>only '$' can in</td>
	 * </tr>
	 * <tr>
	 * 		<td>$</td>
	 * 		<td>only '{' can in, if '$' in, then pop once and return false</td>
	 * </tr>
	 * <tr>
	 * 		<td>{</td>
	 * 		<td>only '}' can in</td>
	 * </tr>
	 * <tr>
	 * 		<td>}</td>
	 * 		<td>only '$' can in</td>
	 * </tr>
	 * </table>
	 * 
	 * @param c: the char
	 * @return <i>true</i>: the char had been put in to stack
	 * 			<br><i>false</i>: fail to push to stack 
	 */
	public boolean push(char c)
	{
		if (ms.empty())
		{
			if (c == marks.markStart())
			{
				ms.push(new Character(c));
				return true;
			}
		}
		else
		{
			char sc = ((Character)ms.peek()).charValue();
			if (sc == marks.markStart())
			{
				if (c == marks.markStart())
				{
					ms.pop();
					return false;
				}
				else if (c == marks.markLeft())
				{
					ms.push(new Character(c));
					return true;
				}
			}
			else if (sc == marks.markLeft() && c == marks.markRight())
			{
				ms.push(new Character(c));
				return true;
			}
			else if (sc == marks.markRight() && c == marks.markStart())
			{
				ms.push(new Character(c));
				return true;
			}
		}
		return false;
	}

	public void clear()
	{
		ms.clear();
	}

	public boolean popPair()
	{
		if (isClosed() && !ms.empty())
		{
			for (int i = 0; i < (marks.markHead().length + 1); i++)
			{
				ms.pop();
			}
			return true;
		}
		return false;
	}

	/**
	 * If stack is like '...[$][{]' or Empty, it is not closed.
	 * <br>
	 * Only '...${}' is mean closed.
	 * 
	 * @return stack is closed or not.
	 */
	public boolean isClosed()
	{
		if (!ms.empty())
		{
			if (ms.size() < (marks.markHead().length + 1))
				return false;
			if (((Character)ms.peek()).charValue() != marks.markRight())
				return false;
			if (((Character)ms.peek(1)).charValue() != marks.markLeft())
				return false;
			return true;
		}
		return false;
	}

	/**
	 * @return stack is empty or not.
	 */
	public boolean isEmpty()
	{
		return ms.empty();
	}

	/**
	 * @return stack is opened.
	 */
	public boolean isOpen()
	{
		if (((Character)ms.peek()).charValue() != marks.markLeft())
			return false;
		if (((Character)ms.peek(1)).charValue() != marks.markStart())
			return false;
		return true;
	}
}